#include "PhyNetPointParser.h"

#include "XformParser.h"
#include "QStringParser.h"
#include "NetPointParser.h"
#include "ExposureParser.h"
#include "FeatureParser.h"
#include "DoubleParser.h"
#include "BoolParser.h"

#include <QXmlStreamReader>
#include <QString>

namespace Ipc2581b
{

PhyNetPointParser::PhyNetPointParser(
    DoubleParser *&_xParser
    , DoubleParser *&_yParser
    , QStringParser *&_layerRefParser
    , QStringParser *&_secondaryLayerRefParser
    , NetPointParser *&_netNodeParser
    , ExposureParser *&_exposureParser
    , QStringParser *&_layerIndexParser
    , QStringParser *&_commentParser
    , BoolParser *&_viaParser
    , BoolParser *&_fiducialParser
    , BoolParser *&_testParser
    , DoubleParser *&_staggerXParser
    , DoubleParser *&_staggerYParser
    , DoubleParser *&_staggerRadiusParser
    , XformParser *&_xformParser
    , FeatureParser *&_featureParser
):    m_xParser(_xParser)
    , m_yParser(_yParser)
    , m_layerRefParser(_layerRefParser)
    , m_secondaryLayerRefParser(_secondaryLayerRefParser)
    , m_netNodeParser(_netNodeParser)
    , m_exposureParser(_exposureParser)
    , m_layerIndexParser(_layerIndexParser)
    , m_commentParser(_commentParser)
    , m_viaParser(_viaParser)
    , m_fiducialParser(_fiducialParser)
    , m_testParser(_testParser)
    , m_staggerXParser(_staggerXParser)
    , m_staggerYParser(_staggerYParser)
    , m_staggerRadiusParser(_staggerRadiusParser)
    , m_xformParser(_xformParser)
    , m_featureParser(_featureParser)
{

}

bool PhyNetPointParser::parse(QXmlStreamReader *reader)
{
    /* Pre */

    m_result.reset(new PhyNetPoint());

    /* Attributes */

    QStringRef data;
    if (reader->attributes().hasAttribute(QStringLiteral("x")))
    {
        data = reader->attributes().value(QStringLiteral("x"));
        if (!m_xParser->parse(reader, data))
            return false;
        m_result->x = m_xParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("x: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("y")))
    {
        data = reader->attributes().value(QStringLiteral("y"));
        if (!m_yParser->parse(reader, data))
            return false;
        m_result->y = m_yParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("y: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("layerRef")))
    {
        data = reader->attributes().value(QStringLiteral("layerRef"));
        if (!m_layerRefParser->parse(reader, data))
            return false;
        m_result->layerRef = m_layerRefParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("layerRef: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("secondaryLayerRef")))
    {
        data = reader->attributes().value(QStringLiteral("secondaryLayerRef"));
        if (!m_secondaryLayerRefParser->parse(reader, data))
            return false;
        m_result->secondaryLayerRefOptional = Optional<QString>(m_secondaryLayerRefParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("netNode")))
    {
        data = reader->attributes().value(QStringLiteral("netNode"));
        if (!m_netNodeParser->parse(reader, data))
            return false;
        m_result->netNode = m_netNodeParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("netNode: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("exposure")))
    {
        data = reader->attributes().value(QStringLiteral("exposure"));
        if (!m_exposureParser->parse(reader, data))
            return false;
        m_result->exposure = m_exposureParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("exposure: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("layerIndex")))
    {
        data = reader->attributes().value(QStringLiteral("layerIndex"));
        if (!m_layerIndexParser->parse(reader, data))
            return false;
        m_result->layerIndexOptional = Optional<QString>(m_layerIndexParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("comment")))
    {
        data = reader->attributes().value(QStringLiteral("comment"));
        if (!m_commentParser->parse(reader, data))
            return false;
        m_result->commentOptional = Optional<QString>(m_commentParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("via")))
    {
        data = reader->attributes().value(QStringLiteral("via"));
        if (!m_viaParser->parse(reader, data))
            return false;
        m_result->viaOptional = Optional<Bool>(m_viaParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("fiducial")))
    {
        data = reader->attributes().value(QStringLiteral("fiducial"));
        if (!m_fiducialParser->parse(reader, data))
            return false;
        m_result->fiducialOptional = Optional<Bool>(m_fiducialParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("test")))
    {
        data = reader->attributes().value(QStringLiteral("test"));
        if (!m_testParser->parse(reader, data))
            return false;
        m_result->testOptional = Optional<Bool>(m_testParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("staggerX")))
    {
        data = reader->attributes().value(QStringLiteral("staggerX"));
        if (!m_staggerXParser->parse(reader, data))
            return false;
        m_result->staggerXOptional = Optional<Double>(m_staggerXParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("staggerY")))
    {
        data = reader->attributes().value(QStringLiteral("staggerY"));
        if (!m_staggerYParser->parse(reader, data))
            return false;
        m_result->staggerYOptional = Optional<Double>(m_staggerYParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("staggerRadius")))
    {
        data = reader->attributes().value(QStringLiteral("staggerRadius"));
        if (!m_staggerRadiusParser->parse(reader, data))
            return false;
        m_result->staggerRadiusOptional = Optional<Double>(m_staggerRadiusParser->result());
    }

    /* Elements */

    while (reader->readNextStartElement())
    {
        auto name = reader->name();
        if (name == QStringLiteral("Xform"))
        {
            if (!m_xformParser->parse(reader))
                return false;
            auto result = m_xformParser->result();
            m_result->xformOptional = Optional<Xform*>(result);
        }
        else if (m_featureParser->isSubstitution(name))
        {
            if (!m_featureParser->parse(reader))
                return false;
            auto result = m_featureParser->result();
            m_result->feature = result;
        }
        else
            reader->skipCurrentElement();
    }

    /* Post */

    // TODO: Check multiplicity of elements/attributes

    return true;
}

PhyNetPoint *PhyNetPointParser::result()
{
    return m_result.take();
}

}